package controller

import (
	"bytes"
	"context"
	"digital/server/common"
	"digital/server/model"
	"digital/server/response"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"github.com/tencentyun/cos-go-sdk-v5"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

func GenerateUniqueFilename(userID int) string {
	timestamp := time.Now().UnixNano() / int64(time.Millisecond)
	return fmt.Sprintf("%d_%d", userID, timestamp) // 假设文件名以.jpg为后缀
}

// 上传
func UploadToCOS(ctx *gin.Context) {
	file, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "文件上传失败"})
		return
	}
	src, err := file.Open()
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
		return
	}
	defer src.Close()
	content, err := ioutil.ReadAll(src)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取文件内容"})
		return
	}

	// 将文件内容放入bytes.Buffer
	var buf bytes.Buffer
	buf.Write(content)

	uid := ctx.PostForm("uid")
	fmt.Println("uid", uid)
	uidInt, err := strconv.Atoi(uid)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "无法转换uid"})
		return
	}
	// 生成唯一的对象键
	objectKey := GenerateUniqueFilename(uidInt) + filepath.Ext(file.Filename)

	// 获取 COS 客户端
	client := common.GetCOS()
	DB := common.GetDB()
	// 设置 COS 上传选项
	opt := &cos.ObjectPutOptions{
		ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
			ContentLength: int64(buf.Len()),
			ContentType:   http.DetectContentType(buf.Bytes()),
		},
	}

	// 上传文件到 COS
	_, err = client.Object.Put(context.Background(), objectKey, &buf, opt)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "上传文件失败: " + err.Error()})
		return
	}

	// 构建访问 URL
	url := fmt.Sprintf("https://%s-%s.cos.%s.myqcloud.com/%s", viper.GetString("cos.bucketName"), viper.GetString("cos.appID"), viper.GetString("cos.region"), objectKey)
	newfile := model.AllFile{
		Filename: file.Filename,
		FileUrl:  url,
	}
	if err := DB.Table("all_file").Create(&newfile).Error; err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败"})
		return
	}
	ctx.JSON(http.StatusOK, gin.H{"message": "文件上传成功", "fileID": newfile.ID})
}

// 删除
func DeleteFromCOS(ctx *gin.Context) {
	fileURL := ctx.Query("fileUrl") // 从查询参数中获取要删除的文件在 COS 中的访问 URL
	fmt.Println("url:", fileURL)
	// 解析文件 URL，获取对象键
	objectKey, err := parseObjectKeyFromURL(fileURL)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件 URL"})
		return
	}

	fmt.Println("url:::", objectKey)
	// 获取 COS 客户端
	client := common.GetCOS()
	// 删除对象
	_, err = client.Object.Delete(context.Background(), objectKey)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "删除文件失败"})
		return
	}
	ctx.JSON(http.StatusOK, gin.H{"message": "文件删除成功"})
	//添加数据库和分表逻辑
}
func UpdateFile(ctx *gin.Context) {
	//删除
	fileURL := ctx.PostForm("fileUrl") // 从查询参数中获取要删除的文件在 COS 中的访问 URL
	// 解析文件 URL，获取对象键
	objectKey, err := parseObjectKeyFromURL(fileURL)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "无效的文件 URL"})
		return
	}
	// 获取 COS 客户端
	client := common.GetCOS()
	// 删除对象
	_, err = client.Object.Delete(context.Background(), objectKey)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "删除文件失败"})
		return
	}
	//上传
	file, err := ctx.FormFile("file")
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "文件上传失败"})
		return
	}
	src, err := file.Open()
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "无法打开文件"})
		return
	}
	defer src.Close()
	content, err := ioutil.ReadAll(src)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "无法读取文件内容"})
		return
	}

	// 将文件内容放入bytes.Buffer
	var buf bytes.Buffer
	buf.Write(content)

	uid := ctx.PostForm("uid")
	uidInt, err := strconv.Atoi(uid)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "无法转换uid"})
		return
	}
	// 生成唯一的对象键
	objectKey1 := GenerateUniqueFilename(uidInt) + filepath.Ext(file.Filename)

	// 获取 COS 客户端
	DB := common.GetDB()
	// 设置 COS 上传选项
	opt := &cos.ObjectPutOptions{
		ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
			ContentLength: int64(buf.Len()),
			ContentType:   http.DetectContentType(buf.Bytes()),
		},
	}

	// 上传文件到 COS
	_, err = client.Object.Put(context.Background(), objectKey1, &buf, opt)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "上传文件失败: " + err.Error()})
		return
	}
	// 构建访问 URL
	url := fmt.Sprintf("https://%s-%s.cos.%s.myqcloud.com/%s", viper.GetString("cos.bucketName"), viper.GetString("cos.appID"), viper.GetString("cos.region"), objectKey1)
	//更新数据库
	fileID := ctx.PostForm("fileID")
	if err := DB.Table("all_file").Where("id=?", fileID).Updates(model.AllFile{
		FileUrl:  url,
		Filename: file.Filename,
	}).Error; err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "保存文件失败"})
		return
	}
	response.Success(ctx, gin.H{"file": gin.H{
		"id":  fileID,
		"url": url,
	}}, "入社申请获取成功!")
	//ctx.JSON(http.StatusOK, gin.H{
	//	"message": "文件上传成功",
	//	"file": gin.H{
	//		"id":  fileID,
	//		"url": url,
	//	},
	//})
}

// 解析文件 URL，提取对象键
func parseObjectKeyFromURL(fileURL string) (string, error) {
	// 示例：假设文件 URL 的格式为 https://<bucketName>-<appID>.cos.<region>.myqcloud.com/<objectKey>
	u, err := url.Parse(fileURL)
	if err != nil {
		return "", err
	}

	// 提取对象键
	objectKey := strings.TrimPrefix(u.Path, "/")

	return objectKey, nil

}

func DownloadFile(c *gin.Context) {
	fileURL := c.Query("FileUrl")
	if fileURL == "" {
		c.String(http.StatusBadRequest, "File URL is empty")
		return
	}

	// 检查协议是否合法
	if !strings.HasPrefix(fileURL, "http://") && !strings.HasPrefix(fileURL, "https://") {
		c.String(http.StatusBadRequest, "Invalid protocol in file URL")
		return
	}

	// 解析文件名
	u, err := url.Parse(fileURL)
	if err != nil {
		c.String(http.StatusBadRequest, "Invalid file URL")
		return
	}
	fileName := filepath.Base(u.Path)

	// 发起对文件 URL 的 GET 请求
	resp, err := http.Get(fileURL)
	if err != nil {
		c.String(http.StatusInternalServerError, fmt.Sprintf("Error fetching file: %v", err))
		return
	}
	defer resp.Body.Close()

	// 设置响应头，告知浏览器文件类型和下载方式
	c.Header("Content-Type", resp.Header.Get("Content-Type"))
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fileName))

	// 将文件流复制到响应中
	_, err = io.Copy(c.Writer, resp.Body)
	if err != nil {
		c.String(http.StatusInternalServerError, fmt.Sprintf("Error streaming file: %v", err))
		return
	}
}
